﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using ProjectEuler.Extensions;
using ProjectEuler.Linq;
using ProjectEuler.Problems;
using System.Windows.Threading;

namespace ProjectEuler.UI
{
    internal sealed class ProblemInfoCollection : ObservableCollection<ProblemInfo>
    {
        public ProblemInfoCollection()
        {
            Dispatcher = Dispatcher.CurrentDispatcher;
            AddProblems(GetType().Assembly.GetTypes());
        }

        public Boolean ShouldRunAll
        {
            get { return this.All(p => p.IsSelected); }
            set { this.ForEach(p => p.IsSelected = value); }
        }

        internal void OnShouldRunAllChanged()
        {
            OnPropertyChanged(new PropertyChangedEventArgs("ShouldRunAll"));
        }

        internal Dispatcher Dispatcher
        {
            get;
            private set;
        }

        private void AddProblems(IEnumerable<Type> types)
        {
            foreach (var pi in from t in types
                               where t.IsSubclassOf(typeof(EulerProblem)) && !t.IsAbstract
                               let attr = t.GetCustomAttribute<EulerProblemAttribute>(false)
                               where attr != null
                               orderby attr.ID ascending
                               select new ProblemInfo(this, t, attr))
            {
                Add(pi);
            }

            if (this.Any(pi => !pi.HasDescription))
            {
                foreach (var pi in this)
                {
                    pi.IsSelected = !pi.HasDescription;
                }
            }
        }
    }
}
